# -*- Python -*-

import os
import platform
import re
import subprocess

try:
    import lit.formats
    import lit.util
except ImportError:
    pass

# Configuration file for the 'lit' test runner.

# name: The name of this test suite.
config.name = 'Covert C++'

# Tweak PATH for Win32
if platform.system() == 'Windows':
    # Seek sane tools in directories and set to $PATH.
    path = getattr(config, 'lit_tools_dir', None)
    path = lit_config.getToolsPath(path,
                                   config.environment['PATH'],
                                   ['cmp.exe', 'grep.exe', 'sed.exe'])
    if path is not None:
        path = os.path.pathsep.join((path,
                                     config.environment['PATH']))
        config.environment['PATH'] = path

# Choose between lit's internal shell pipeline runner and a real shell.  If
# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
if use_lit_shell:
    # 0 is external, "" is default, and everything else is internal.
    execute_external = (use_lit_shell == "0")
else:
    # Otherwise we default to internal on Windows and external elsewhere, as
    # bash on Windows is usually very slow.
    execute_external = (not sys.platform in ['win32'])

# testFormat: The test format to use to interpret tests.
#
# For now we require '&&' between commands, until they get globally killed and
# the test runner updated.
config.test_format = lit.formats.ShTest(execute_external)

# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.c', '.cpp']

# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)

# test_exec_root: The root path where tests should be run.
covert_bin_root = getattr(config, 'covert_bin_root', None)
llvm_dir = getattr(config, 'llvm_dir', None)

if covert_bin_root is not None:
    config.test_exec_root = os.path.join(covert_bin_root, 'test')

llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
# Tweak the PATH to include the LLVM bin dir.
if not llvm_tools_dir:
    lit_config.fatal('Could not find the LLVM installation bin directory!')
config.environment['PATH'] = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))

# Tweak the PATH to include the tools dir.
covert_tools_dir = getattr(config, 'covert_tools_dir', None)
if not covert_tools_dir:
    lit_config.fatal('No Covert C++ tools dir found!')
config.environment['PATH'] = os.path.pathsep.join((covert_tools_dir, config.environment['PATH']))

covert_include_dir = getattr(config, 'covert_include_dir', None)
if not covert_include_dir:
    lit_config.fatal('No Covert C++ headers dir found!')

# Check that the object root is known.
if config.test_exec_root is None:
    lit.fatal('test execution root not set!')

def inferOpt(PATH):
    # Determine which opt to use.
    opt = os.getenv('LLVM_OPT')

    # If the user set clang in the environment, definitely use that and don't
    # try to validate.
    if opt:
        return opt

    # Otherwise look in the path.
    opt = lit.util.which('opt', PATH)

    if not opt:
        lit_config.fatal("couldn't find 'opt' program, try setting "
                         "LLVM_OPT in your environment")

    return opt


def inferClang(PATH):
    # Determine which clang to use.
    clang = os.getenv('CLANG')

    # If the user set clang in the environment, definitely use that and don't
    # try to validate.
    if clang:
        return clang

    # Otherwise look in the path.
    clang = lit.util.which('clang', PATH)

    if not clang:
        lit_config.fatal("couldn't find 'clang' program, try setting "
                         "CLANG in your environment")

    return clang

def inferLLI(PATH):
    # Determine which lli to use.
    lli = os.getenv('LLI')

    # If the user set lli in the environment, definitely use that and don't
    # try to validate.
    if lli:
        return lli

    # Otherwise look in the path.
    lli = lit.util.which('lli', PATH)

    if not lli:
        lit_config.fatal("couldn't find 'lli' program, try setting "
                         "LLI in your environment")

    return lli

def inferFileCheck(PATH):
    # Determine which FileCheck to use.
    FileCheck = os.getenv('FILECHECK')

    # If the user set FILECHECK in the environment, definitely use that and don't
    # try to validate.
    if FileCheck:
        return FileCheck

    # Otherwise look in the path.
    FileCheck = lit.util.which('FileCheck', PATH)

    if not FileCheck:
        lit_config.fatal("couldn't find 'FileCheck' program, try setting "
                         "FILECHECK in your environment")

    return FileCheck

config.opt = inferOpt(config.environment['PATH']).replace('\\', '/')
if not lit_config.quiet:
    lit_config.note('using opt: %r' % config.opt)
config.clang = inferClang(config.environment['PATH']).replace('\\', '/')
if not lit_config.quiet:
    lit_config.note('using clang: %r' % config.clang)
config.lli = inferLLI(config.environment['PATH']).replace('\\', '/')
if not lit_config.quiet:
    lit_config.note('using lli: %r' % config.lli)
config.FileCheck = inferFileCheck(config.environment['PATH']).replace('\\', '/')
if not lit_config.quiet:
    lit_config.note('using FileCheck: %r' % config.FileCheck)

# Set additional compiler flags
clang_common_flags = []
lli_common_flags = []

cpp_std = getattr(config, 'cpp_std', None)
if not cpp_std:
    lit_config.fatal("No C++ standard specified")
clang_common_flags.append('-std=' + cpp_std)
clang_common_flags.append('-x c++')
clang_common_flags.append('-I\"' + covert_include_dir + '\"')

if platform.system() != 'Windows':
    libcxx_include_dir = getattr(config, 'libcxx_include_dir', None)
    if not libcxx_include_dir:
        lit_config.fatal("No libc++ headers provided")
    clang_common_flags.append('-nostdinc++')
    clang_common_flags.append('-I\"' + libcxx_include_dir + '\"')
    libcxx = getattr(config, 'libcxx', None)
    if not libcxx:
        lit_config.fatal("No libc++ library provided")
    lli_common_flags.append('-load=\"' + libcxx + '\"')

clang_common_flags_str = ' '.join(clang_common_flags)
lli_common_flags_str = ' '.join(lli_common_flags)
obl_run_flag = ' -load=' + config.Oblivious + ' '
obl_build_flags = ' -mavx2 ' + '-I' + covert_bin_root + '/include/Oblivious' + ' '

config.substitutions.append( ('%clang-llvmo', ' \"' + config.clang + '\" ' + clang_common_flags_str + ' -c -emit-llvm -fno-use-cxa-atexit ' + obl_build_flags) )
config.substitutions.append( ('%clang-llvm', ' \"' + config.clang + '\" ' + clang_common_flags_str + ' -c -emit-llvm -fno-use-cxa-atexit ') )
config.substitutions.append( ('%opt', ' \"' + config.opt + '\" -O3 ') )
config.substitutions.append( ('%clang-syntaxo', ' \"' + config.clang + '\" ' + clang_common_flags_str + ' -fsyntax-only ' + obl_build_flags) )
config.substitutions.append( ('%clang-syntax', ' \"' + config.clang + '\" ' + clang_common_flags_str + ' -fsyntax-only ') )
config.substitutions.append( ('%llio', ' \"' + config.lli + '\" ' + lli_common_flags_str + ' ' + obl_run_flag) )
config.substitutions.append( ('%lli', ' \"' + config.lli + '\" ' + lli_common_flags_str + ' ') )
config.substitutions.append( ('%FileCheck', ' \"' + config.FileCheck + '\" ') )
